#define GL_GLEXT_PROTOTYPES
#include <Enesim.h>
#include <Enesim_OpenGL.h>

#include <X11/Xlib.h>
#include <GL/glx.h>
#include <GL/glext.h>


static GLXContext _context = NULL;
static GLXWindow _glx_win;
static GLXFBConfig _config;
static Window _win;
static Window _root;
static Display *_display;
static int _screen;
static Enesim_Pool *_pool;
static Enesim_Renderer *r;
static Enesim_Path *p;

#define WIDTH 320
#define HEIGHT 240

#define GLERR {\
        GLenum err; \
        err = glGetError(); \
        printf("Error %d\n", err); \
        }

int c = 4;

static void _renderer_setup(void)
{
	switch (c)
	{
		case 0:
		r = enesim_renderer_background_new();
		enesim_renderer_background_color_set(r, 0xffff0000);
		break;

		case 1:
		r = enesim_renderer_checker_new();
		enesim_renderer_checker_odd_color_set(r, 0xffff00ff);
		enesim_renderer_checker_even_color_set(r, 0xffff0000);
		enesim_renderer_checker_width_set(r, 30);
		enesim_renderer_checker_height_set(r, 30);
		break;

		case 2:
		r = enesim_renderer_stripes_new();
		enesim_renderer_stripes_odd_color_set(r, 0xffffffff);
		enesim_renderer_stripes_even_color_set(r, 0xff000000);
		enesim_renderer_stripes_odd_thickness_set(r, 10);
		enesim_renderer_stripes_even_thickness_set(r, 20);
		break;

		case 3:
		r = enesim_renderer_rectangle_new();
		enesim_renderer_rectangle_position_set(r, 8.5, 8.5);
		enesim_renderer_rectangle_size_set(r, 50, 50);
		enesim_renderer_shape_fill_color_set(r, 0xffff0000);
		enesim_renderer_shape_stroke_weight_set(r, 18);
		enesim_renderer_shape_stroke_color_set(r, 0xff00ffff);
		enesim_renderer_shape_draw_mode_set(r, ENESIM_RENDERER_SHAPE_DRAW_MODE_FILL);
		break;

		case 4:
		r = enesim_renderer_path_new();
		p = enesim_renderer_path_path_get(r);
		enesim_path_move_to(p, 2*12, 2*27);
		enesim_path_cubic_to(p, 2*7, 2*37, 2*18, 2*50, 2*18, 2*60);
		enesim_path_scubic_to(p, 2*0, 2*80, 2*10, 2*94);
		enesim_path_scubic_to(p, 2*40, 2*74, 2*50, 2*78);
		enesim_path_scubic_to(p, 2*60, 2*99, 2*76, 2*95);
		enesim_path_scubic_to(p, 2*72, 2*70, 2*75, 2*65);
		enesim_path_scubic_to(p, 2*95, 2*55, 2*95, 2*42);
		enesim_path_scubic_to(p, 2*69, 2*37, 2*66, 2*32);
		enesim_path_scubic_to(p, 2*67, 2*2, 2*53, 2*7);
		enesim_path_scubic_to(p, 2*43, 2*17, 2*35, 2*22);
		enesim_path_scubic_to(p, 2*17, 2*17, 2*12, 2*27);
		enesim_renderer_shape_stroke_weight_set(r, 18);
		enesim_renderer_shape_stroke_color_set(r, 0xff00ffff);
		enesim_renderer_shape_fill_color_set(r, 0xffff0000);
		//enesim_renderer_shape_draw_mode_set(r, ENESIM_RENDERER_SHAPE_DRAW_MODE_STROKE_FILL);
		enesim_renderer_shape_draw_mode_set(r, ENESIM_RENDERER_SHAPE_DRAW_MODE_STROKE);
		break;

		default:
		break;
	}
}

static int _x_setup(void)
{
	char *display_name;

	display_name = XDisplayName(NULL);
	_display = XOpenDisplay(display_name);
	if (!_display)
	{
		printf("Impossible to open display\n");
		return 0;
	}

	_root = DefaultRootWindow(_display);
	_screen = DefaultScreen(_display);

	return 1;
}

static void _x_window_setup(void)
{
	XSetWindowAttributes swa;
	XVisualInfo *vInfo;
	int swaMask;

	vInfo = glXGetVisualFromFBConfig(_display, _config);
	swa.border_pixel = 0;
	swa.event_mask = StructureNotifyMask;
	swa.colormap = XCreateColormap(_display, _root, vInfo->visual, AllocNone);

	swaMask = CWBorderPixel | CWColormap | CWEventMask;

	_win = XCreateWindow(_display, _root, 0, 0, WIDTH, HEIGHT,
			0, vInfo->depth, InputOutput, vInfo->visual,
			swaMask, &swa);

	XSelectInput(_display, _win, ExposureMask | KeyPressMask);
	XMapWindow(_display, _win);
}

static int _glx_setup(void)
{
	GLXFBConfig *fbConfigs;
	int sb_attributes[] = {
		GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
		GLX_RENDER_TYPE,   GLX_RGBA_BIT,
		GLX_DOUBLEBUFFER,  True,
		GLX_RED_SIZE,      1,
		GLX_GREEN_SIZE,    1,
		GLX_BLUE_SIZE,     1,
		None
	};
	int num_fbs;

	/* try to create a glx context for the given window */
	fbConfigs = glXChooseFBConfig(_display, _screen, sb_attributes, &num_fbs);
	_config = fbConfigs[0];
	/* Create a GLX context for OpenGL rendering */
	_context = glXCreateNewContext(_display, _config, GLX_RGBA_TYPE, NULL, True);
	if (!_context)
	{
		printf("Not possible to create the glx context\n");
		return 0;
	}
	_x_window_setup();
	_glx_win = glXCreateWindow(_display, _config, _win, NULL);
	if (!_glx_win)
	{
		printf("Not possible to create the glx window\n");
		return 0;
	}
	if (glXMakeContextCurrent(_display, _glx_win, _glx_win, _context) != True)
	{
		printf("Impossible to make context current");
		return 0;
	}
	return 1;
}

static int _gl_setup(void)
{
	_pool = enesim_pool_opengl_new();
	if (!_pool)
	{
		printf("Failed to create the pool\n");
		return 0;
	}
	return 1;
}

static void _display_surface(Enesim_Surface *s)
{
	Enesim_Buffer_OpenGL_Data *data;

	data = enesim_surface_opengl_data_get(s);

	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);

	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
	glBindTexture(GL_TEXTURE_2D, data->texture);

	glClearColor(1.0, 1.0, 1.0, 1.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
	glOrtho(0, WIDTH, 0, HEIGHT, -1, 1);

	glViewport(0, 0, WIDTH, HEIGHT);

	glMatrixMode(GL_TEXTURE);
        glLoadIdentity();

	glBegin(GL_QUADS);
		glTexCoord2d(0, 0); glVertex2f(0, 0);
		glTexCoord2d(1, 0); glVertex2f(WIDTH, 0);
		glTexCoord2d(1, 1); glVertex2f(WIDTH, HEIGHT);
		glTexCoord2d(0, 1); glVertex2f(0, HEIGHT);
        glEnd();
}

int main(int argc, char **argv)
{
	Enesim_Surface *s;
	XEvent e;

	if (!_x_setup())
		return 1;
	if (!_glx_setup())
		return 1;

	if (argc > 1)
		c = atoi(argv[1]);
	enesim_init();
	//enesim_image_init();
	if (!_gl_setup())
	{
		enesim_shutdown();
		return 1;
	}

	/* create our pool */
	s = enesim_surface_new_pool_from(ENESIM_FORMAT_ARGB8888, 320, 240, _pool);
	if (!s)
	{
		printf("Impossible to create the surface\n");
		return 0;
	}

	_renderer_setup();
	while (1)
	{
		XNextEvent(_display, &e);

		if (e.type == Expose) {
			Eina_Rectangle area;

			eina_rectangle_coords_from(&area, 0, 0, 160, 120);
			/* draw something */
			enesim_renderer_draw(r, s, ENESIM_ROP_FILL, NULL, 0, 0, NULL);
			_display_surface(s);
			//XFillRectangle(_display, _win, DefaultGC(_display, _screen), 20, 20, 10, 10);
			glXSwapBuffers(_display, _glx_win);
		}
		if (e.type == KeyPress) {
			break;
		}
	}
	//enesim_image_file_save(fout, dst, NULL);

	enesim_surface_unref(s);
	enesim_pool_unref(_pool);
	//enesim_image_shutdown();
	enesim_shutdown();

	return 0;
}

